using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using Customer;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;

namespace WindowsFormsApplication1
{
    public partial class StartAndStopPour : Form
    {
        Stopwatch stopWatch = new Stopwatch();
        int combined;
        string amount;
        double poured;
        bool allowPour = true;
        bool allowFinish = true;

        string cardNum;
        Person person;
        BitArray status;
        string[] drink = new string[14];        
        byte tempByte;
        BeverageSizeSelect SizeSelectForm;
        byte[] status_byte = new byte[1];

        // variables for sending order to bartender
        byte[] data = new byte[1024];
        string stringData;
        string ipAddress = "10.40.136.93";//"10.40.163.142";//"10.40.167.6";//"10.254.254.253";//"10.40.137.203";
        int portNumber = 9050;
        IPEndPoint ipep;
        Socket server; 
        string drinkOrderRevised;
        string message;

        // variables for receiving data from bartender
        IPEndPoint Sender;
        EndPoint Remote;
        int recv;

        // variables for receiving data from the microcontroller
        int length;
        byte[] PICByte_Buffer;
        BitArray PICStatus;
        int bitLength;
        int limit;

        TimeSpan ts;

        //need to pass in the size that the person chose, or infinity if it is a PPO
        public StartAndStopPour(Person Person, BitArray Status, BeverageSizeSelect sizeSelectForm)
        {
            person = Person;
            cardNum = person.CardNumber;
            drink = Person.Drink;
            SizeSelectForm = sizeSelectForm;            
            if (cardNum == "b") {
                //price = 0.0m;
            }
            else {
                //price = .25m;
            }

            status = Status;
            InitializeComponent();
            beginButton.Enabled = true;
            stopButton.Enabled = false;
            //configuring the serial port
            serialPort1.PortName = "COM6";
            serialPort1.BaudRate = 9600;
            serialPort1.DataBits = 8;
            serialPort1.Parity = Parity.None;
            serialPort1.StopBits = StopBits.One;        
              
        }

        private void beginButton_Click(object sender, EventArgs e)
        {
            if (allowPour)
            {
                allowFinish = false;
                // set bits 1 and 2 of status indicating that the microcontroller should start pouring
                status[0] = true; status[1] = true; status[2] = true; status[7] = false;                
                status.CopyTo(status_byte, 0);
                serialPort1.Write(status_byte, 0, 1);
                stopButton.Enabled = true;
                beginButton.Enabled = false;
                exitButton.Visible = false;
            }
        }
        
        private void stopButton_Click(object sender, EventArgs e)
        {
            if (allowPour)
            {
                allowFinish = true;
                // clear bit 2 of status indicating that the microcontroller should stop pouring
                status[0] = true; status[1] = true; status[2] = false; status[7] = false;
                status.CopyTo(status_byte, 0);
                // send status to microcontroller
                serialPort1.Write(status_byte, 0, 1);
                stopButton.Enabled = false;
                beginButton.Enabled = true;
                exitButton.Visible = true;
            }
        }

        private void exitButton_Click(object sender, EventArgs e)
        {
            if (allowFinish)
            {
                status[7] = true;
                status.CopyTo(status_byte, 0);
                serialPort1.Write(status_byte, 0, 1);

                // clear all the status bits 
                status[0] = false; status[1] = false; status[2] = false;
                status[4] = false; status[5] = false; status[6] = false;
                status[7] = false;

                status.CopyTo(status_byte, 0);
                serialPort1.Close();

                // send order to bartender 
                ipep = new IPEndPoint(IPAddress.Parse(ipAddress), portNumber);
                server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                drinkOrderRevised = "@" + cardNum + "#" + amount + "#" + "field3" + "#";

                data = Encoding.ASCII.GetBytes(drinkOrderRevised);
                // try sending the data to the server
                try
                {
                    server.SendTo(data, data.Length, SocketFlags.None, ipep);
                }
                catch (SocketException ex)
                {
                    message = ex.Message;
                    System.Windows.Forms.MessageBox.Show(message);
                }

                // set up new connection
                Sender = new IPEndPoint(IPAddress.Any, 0);
                Remote = (EndPoint)Sender;
                data = new byte[2048];
                try
                {
                    recv = server.ReceiveFrom(data, ref Remote);
                    stringData = Encoding.ASCII.GetString(data, 0, recv);
                }
                catch (SocketException ex)
                {
                    message = ex.Message;
                    System.Windows.Forms.MessageBox.Show(message + " \nYou will not be charged for this order");
                    stringData = "No Host Detected";
                }
                status[7] = false;
                allowFinish = false;
                ThankYouForm thankYouForm = new ThankYouForm(person, stringData, status);
                this.Close();
                thankYouForm.ShowDialog();
            }
            else
            {
                MessageBox.Show("You Must Stop Pouring Before You Can Finish");
            }
        }
        
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // receive data from the microcontroller 
            length = serialPort1.BytesToRead;
            PICByte_Buffer = new byte[length];
            // read the appropriate amount of bytes
            serialPort1.Read(PICByte_Buffer, 0, PICByte_Buffer.Length);
            PICStatus = new BitArray(PICByte_Buffer);
            bitLength = PICStatus.Length;
            limit = serialPort1.BytesToRead;
           
            // if the microcontroller has sent the status byte and the two volume bytes
            if (PICByte_Buffer.Length >= 3) {                
                combined = PICByte_Buffer[PICByte_Buffer.Length - 2] << 8 | PICByte_Buffer[PICByte_Buffer.Length - 1];
                amount = combined.ToString();
                poured = combined / 165.61176;
                updateLabelText((Math.Round(poured,1)).ToString());              
                // get the status byte from the byte array
                tempByte = PICByte_Buffer[PICByte_Buffer.Length - 3];
                
                // check the status     
                // if bit 0 was not zero, then this indicates an error, check what kind of error
                if ((tempByte & 1) != 1) {
                    //MessageBox.Show("Error");
                    allowFinish = true;
                    // if the second bit is zero, there was not a cup present
                    if ((tempByte & 4) != 4) {
                        this.Invoke(new EventHandler(CupErrorMessage));
                        //System.Windows.Forms.MessageBox.Show("Place Cup And Press Start Again");
                        //MessageBox.Show(Convert.ToString(tempByte));                 
                        this.Invoke(new EventHandler(UpdateButtons));
         
                    }
                }
                else if ((tempByte & 2) != 2) {
                    this.Invoke(new EventHandler(VolumeReachedMessage));
                    //updateLabelText("Volume Limit Reached Please Proceed To Checkout");
                    allowPour = false;
                    allowFinish = true;
                }
            }
        }

        // functions to update the amount poured label with 
        delegate void updateLabelTextDelegate(string newText);
        private void updateLabelText(string newText)
        {
            if (volumePoured.InvokeRequired) {
                //this is the worker thread
                updateLabelTextDelegate del = new updateLabelTextDelegate(updateLabelText);
                volumePoured.Invoke(del, new object[] { "You have poured " + newText + " ounces" });
            }
            else{
                //this is the UI thread
                volumePoured.Text = newText;
            }
        }

        private void CupErrorMessage(object sender, EventArgs e)
        {
            volumePoured.Text = "Please Hold Down Lever With Cup And Begin Pouring Again";
            exitButton.Visible = true;

        }

        private void VolumeReachedMessage(object sender, EventArgs e)
        {
            volumePoured.Text = "Desired Volume Has Been Reached, Please Proceed To Checkout";
            exitButton.Visible = true;
        }


      private void UpdateButtons(object sender, EventArgs e)
      {
          beginButton.Enabled = true;
          stopButton.Enabled = false;
      }


        private void StartAndStopPour_Load(object sender, EventArgs e)
        {
            // try opening the serial port ocnnection
            exitButton.Visible = false;
            try
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                }
                serialPort1.Open();
                beginButton.Enabled = true;
                // if it is successful, set bit 0, and clear bit 1 indicating a new order
                status[0] = true;                
                status[2] = false;
                status[7] = false;

                status.CopyTo(status_byte, 0);
                serialPort1.Write(status_byte, 0, 1);
                serialPort1.DiscardInBuffer();
                priceLabel.Text = "The Price Per Ounce is: $" + drink[13];
                status[1] = true;
            }
            catch (Exception ex)
            {
                string message = ex.Message;
                //System.Windows.Forms.MessageBox.Show(message);
                MessageBox.Show("Error Pouring Beer, Please Ask For Assistance");
                this.Close();
            }              
        }

        private void helpButton_Click(object sender, EventArgs e)
        {
            string helpMessage = "You may control when you drink is poured by hitting the begin and " +
                "stop pouring buttons.  If you selected a predetermined size, when this limit is detected, " +
                "the flow will be stopped.  If you are paying per ounce, you may pour up to 180 oz during " +
                "a single purchase.";
            HelpForm helpForm = new HelpForm(helpMessage);
            helpForm.ShowDialog();
        }
    
    }
}



/* 
in the start pouring function
TimeSpan ts = stopWatch.Elapsed;
string hours = ts.Hours.ToString();
string milliseconds = ts.Milliseconds.ToString();
string[] lines = { "The number of milliseconds poured was " + milliseconds + "    " };            
System.IO.File.AppendAllLines(@path, lines);
in the stop pouring function
// code to tell microcontroller to stop pouring
            stopWatch.Stop();
 
 */